<?php
/**
 * 
 * 理想表结构是 一个pri，
*@package TTable.cls.php
*@copyright Copyright (c) 2012-2014 Tuniu.com
*@author huxiaomin 2012  上午09:10:47
*@version 1.0
*/

class TTable{

	private $table_name = '';
	private $db;
	private $PRI = array();
	private $desc = array();
	
	public  $cache = 1;
	
	private  $table='';
	//缓存文件夹
	static $folders = array();
	
	function __construct($table_name){
		$this->db = DDb::Dao();
		
		if (empty($table_name)){
		  $this->table = $this->db;
		  return;
		}
		
		$this->table_name = $table_name;
		$table_class =  strtr(ucwords(strtr($table_name,'_',' ')), array(' '=>''));
		$load = $this->load($table_class);
		if ($load) {
			$table_class .= 'Table';
			$this->table = new $table_class();
			$this->table->ttable = &$this;
			$this->table->db = $this->db;
		}
		$this->getDesc();
	}

	function load($table_class){
    	$dir = TTABLE_DIR;
    	if (file_exists($dir.$table_class.TTABLE_SUFFIX)){
    	   require_once $dir.$table_class.TTABLE_SUFFIX;
    	   return true;
    	}
    	else {
    	   $dirs_arr = self::getFolder($dir);
    	   foreach ($dirs_arr as $v){
    	       if (file_exists($v.'/'.$table_class.TTABLE_SUFFIX)){
    	           require_once $v.'/'.$table_class.TTABLE_SUFFIX;
    	           return true;
    	       }
    	   }
    	}
    	return false;
    	
    }
    
    /**
     * 返回文件夹 
     * @param string $dir
     * @return array
     */
    static function getFolder($dir){
        if (self::$folders){
            return self::$folders;
        }
        
    	$TMemcache = new TMemcache();
    	$gCacheKey = gCacheKey($dir);
    	$cache_value = $TMemcache->get($gCacheKey);
    	if ($cache_value){
    	   self::$folders = $cache_value;
    	   return $cache_value;
    	}
        
    	$res = opendir($dir);
        $return = array();
        if (!$res){
            return $return;
        }   
        
        while ($f = readdir($res)){
            if (is_dir($dir.$f) && $f{0} !== '.'){
                $return[] = $dir.$f;
            }
        }
        self::$folders = $return;
        
        $TMemcache->set($gCacheKey,$return,0,3600*24);
        return $return;
    }
	
	
	/**
	 * 获取表结构
	 */
    function getDesc($cache_refresh=0){
    	if ($this->desc){
    	   return array($this->PRI,$this->desc);
    	}
    	$TMemcache = new TMemcache();
    	$sql = "show full fields from {$this->table_name}";
    	$gCacheKey = gCacheKey($sql);
    	if ($cache_refresh == 0){
	    	$cache_value = $TMemcache->get($gCacheKey);
	    	if ($cache_value){
	    	   $this->PRI = $cache_value[0];
	    	   $this->desc = $cache_value[1];
	    	   //echo '使用缓存了'.$gCacheKey;
	    	   return '';
	    	}
    	}
    	
    	$desc = $this->db->GetPlan2($sql,'Field','',1);
    	foreach ($desc as $key => $value){
    		$type = explode('(', $value['Type']);
    		$desc[$key]['simple_type'] = $type[0];
    		$desc[$key]['pri'] = strtoupper($value['Key']) === 'PRI';
    		if ($desc[$key]['pri']){
    			$this->PRI[] = $key;
    		}
    	}
    	$this->desc = $desc;
    	
    	$value = array($this->PRI,$this->desc);
    	$TMemcache->set($gCacheKey,$value,0,3600*24);
    	return $value;
    }
    
    /**
     * 格式化表数据
     * @param string $fields
     * @return Array 
     */
    function formart($fields){
    	$set = array(); //用于update的set
    	$insert = array();//用于insert的fields
    	$values = array();//用于insert的values
    	$pri   =  array(); //所有的关键词
    	
    	foreach ((array)$this->desc as $field => $desc){
    		 if (key_exists($field, $fields)){
    		 	 $insert[$field] = "`{$field}`";
    		 	 
    		 	 $value = $fields[$field]; 
    		 	 $values[$field] = DDataFormat::getNumber($value, $desc['simple_type']);
    		 	 $set[$field] = "{$insert[$field]}={$values[$field]}";

    		 }
    	}
    	
    	foreach ((array)$this->PRI as $pri_key){
    		if (key_exists($pri_key, $values)){
    			$pri[$pri_key] = $set[$pri_key];
    		}
    	}
    	
    	return array('insert'=>$insert, 
    				 'values'=>$values,
    				 'set'=>$set, 
    				 'pri'=>$pri
    				 );
    }
    
    /**
     * 插入操作 
     * @param array $fields
     * @param resource $db
     */
    function insert($fields, $db=''){
    	$return = $this->formart($fields);
    	if (!$db){
    		$db = $this->db;
    	}
    	$insert = implode(',', $return['insert']);
    	$values = implode(',', $return['values']);
    	$sql = "INSERT INTO {$this->table_name} 
    		  ({$insert})
    		  VALUES
    		  ({$values})";
    	if ($db->Query($sql)){
    		return $db->LastId();
    	}else {
    		//TODO log
    		return false;
    	}
    }
    
    /**
     * 更新操作
     * @param array $fields
     * @param resource $db
     */
    function update($fields, $db=''){
    	$return = $this->formart($fields);
    	if (!$db){
    		$db = $this->db;
    	}
    	$where = implode(' AND ', $return['pri']);
    	$set = implode(',', $return['set']);
    	if (!$where || !$set){
    		//TODO log
    		return false;
    	}
    	
    	$sql = "UPDATE {$this->table_name}
    			SET {$set}
    			WHERE {$where} LIMIT 1";
    	return $db->Query($sql);
    }
    
    /**
     * 查询语句
     * @param string $fields
     * @param string $where
     * @param string $order
     * @param int $limit
     * @return Array
     */
    private function select($fields, $where, $order ,$limit=500, $db=''){
    	if (!$db){
    		$db = TTableMs::getMs(1);
    	}
    	$sql = "SELECT {$fields}
    			FROM {$this->table_name}";
    	if ($where){
    			$sql .=" WHERE {$where}";
    	}
    	if ($order){
    		$sql .= " ORDER BY {$order}";
    	}
    	$sql .= " LIMIT {$limit}";
    	return $db->GetPlan($sql);
    	
    }
    
    /**
     * where 是数组。 3个值。
     * @param $fields
     * @param $where array
     * @param $order
     * @param $limit
     * @param $db
     */
    private function get($fields,$where,$order,$limit=500,$db=''){
        if (!$db){
            $db = TTableMs::getMs(1);
        }
        $sql = "SELECT {$fields}
                FROM {$this->table_name}";
        if ($where){
        	foreach ((array)$where as $key=>$v){
                $field = $v[0];
                $value = $v[1];
                $compare = $v[2] ? $v[2] : '=';
                $simple_type = $this->desc[$field]['simple_type'];
                if (strtolower($compare) == 'in'){
                    $arr = explode(',' , $value);
                    foreach ((array)$arr as $k=>$v_arr){
                    	$arr[$k] = DDataFormat::getNumber($v_arr, $simple_type);
                    }
                    $value = implode(',',$arr);
                }else {
                    $value = DDataFormat::getNumber($value, $simple_type); 
                }
                $where[$key] = "`{$field}`{$compare}{$value}";
        	}
        	$sql .= ' WHERE '.implode(' AND ',$where);
        }
        if ($order){
            $sql .= " ORDER BY {$order}";
        }
        $sql .= " LIMIT {$limit}";
        return $db->GetPlan($sql); 
    }
    
    
	function __call($name, $params){
		$args = array(&$this->table,&$name,&$params);
		TPlugin::start('TTable',$args);
		
		$cache = array();
		if ($this->table_name && $this->cache){
		  $TTableMemcache = new TTableMemcache();
          $cache = $TTableMemcache->getCallCache($this->table_name,$name,$params);
		}
	    if ($cache['success']){
          $return = $cache['cache'];
        }
        else if ($name == 'select' || $name == 'get' ){
          $return = call_user_func_array(array($this,$name), $params);
        }
        else {
          $return = call_user_func_array(array($this->table,$name), $params);
        }
        if ($cache['need_set']){
            $TTableMemcache->setCallCache($cache['key'], $return,'', $cache['time_out']);
        }
        return $return;
    }
    
    function __get($name){
        return $this->table->$name;
    }
    
    function __set($name,$value){
        return $this->table->$name = $value;
    }

}